﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using App.Domain;
using App.Web.ViewModels;
using App.Core.Extensions;
using AutoMapper;
using System.Text;
using System.Configuration;
using App.Core.DB;

namespace App.Web.Utility
{
    public class BootStrapper
    {
        /// <summary>
        /// Configures the AutoMapper with appropriate Domain DataModel and UI ViewModel types
        /// </summary>
        public static void ConfigureTypeMappings()
        {
            ///Mapper needed for auto converters
            DateTimeToStringConverter dateToString = new DateTimeToStringConverter();
            StringToDateTimeConverter stringToDateTime = new StringToDateTimeConverter();
            StringToNullableDateTimeConverter stringToNullableDateTimeConverter = new StringToNullableDateTimeConverter();
            Mapper.CreateMap<String, DateTime>().ConvertUsing(stringToDateTime);
            Mapper.CreateMap<String, DateTime?>().ConvertUsing(stringToNullableDateTimeConverter);
            Mapper.CreateMap<DateTime, String>().ConvertUsing(dateToString);

            StringToBoolean stringToBoolean = new StringToBoolean();
            BooleanToString booleanToString = new BooleanToString();
            Mapper.CreateMap<String, bool>().ConvertUsing(stringToBoolean);
            Mapper.CreateMap<bool, String>().ConvertUsing(booleanToString);

            IntToNullableInt intToNullableInt = new IntToNullableInt();
            Mapper.CreateMap<int, int?>().ConvertUsing(intToNullableInt);

            ///AutoMapper configuration for IndustryType Entity
            Mapper.CreateMap<IndustryType, IndustryTypeViewModel>();
            Mapper.CreateMap<IndustryTypeViewModel, IndustryType>();

            ///User Mapper
            Mapper.CreateMap<User, UserViewModel>();
            Mapper.CreateMap<UserViewModel, User>();

            ///User Mapper
            Mapper.CreateMap<Group, GroupViewModel>();
            Mapper.CreateMap<GroupViewModel, Group>();

            ///Product Mapper
            Mapper.CreateMap<Product, ProductViewModel>();
            Mapper.CreateMap<ProductViewModel, Product>().ForMember(P => P.ProductImages, O => O.Ignore());

            ///ProductImage Mapper
            Mapper.CreateMap<ProductImage, ProductImageViewModel>();//.ForMember(P => P.CropProperty, Opt => Opt.Ignore());
            Mapper.CreateMap<ProductImageViewModel, ProductImage>();

            ///Product Category Mapper
            Mapper.CreateMap<Category, CategoryViewModel>();
            Mapper.CreateMap<CategoryViewModel, Category>();

            ///Company Mapper
            Mapper.CreateMap<Company, CompanyViewModel>();
            Mapper.CreateMap<CompanyViewModel, Company>();

            ///Contact Mapper
            Mapper.CreateMap<Contact, ContactViewModel>();
            Mapper.CreateMap<ContactViewModel, Contact>();

            ///Content Mapper
            Mapper.CreateMap<Content, ContentViewModel>();
            Mapper.CreateMap<ContentViewModel, Content>();

            ///Store Mapper
            Mapper.CreateMap<Store, StoreViewModel>();
            Mapper.CreateMap<StoreViewModel, Store>();

            ///UOM Mapper
            Mapper.CreateMap<UOM, UOMViewModel>();
            Mapper.CreateMap<UOMViewModel, UOM>();

            //Transaction
            Mapper.CreateMap<Transaction, TransactionViewModel>();
            Mapper.CreateMap<TransactionViewModel, Transaction>();
            
            ///TransactionDetail
            Mapper.CreateMap<TransactionDetail, TransactionDetailViewModel>();
            Mapper.CreateMap<TransactionDetailViewModel, TransactionDetail>();

            #region LGL Mappings
            ///LGL Mappings
            //Mapper.CreateMap<ViewModels.LGL.Category.Category, ViewModels.LGL.Product.Product>();
            #endregion LGL Mapping
        }

        /// <summary>
        /// Caches the User Groups in the Application Context
        /// </summary>
        public static void SetUserRoles()
        {
            AppEntities context = new AppEntities();
            if (context.IsConnected())
            {
                var groups = context.Groups;
                StringBuilder sb = new StringBuilder();
                foreach (Group group in groups)
                {
                    if (sb.Length == 0)
                        sb.Append(group.Name);
                    else
                        sb.AppendFormat(",{0}", group.Name);
                }
                App.Core.Authentication.AppAuthorizeAttribute.UserRoles = sb.ToString();
            }
        }

        /// <summary>
        /// Initialize and prepare various domain utilities
        /// </summary>
        public static void PrepareDomainUtility()
        {
            //String connectionString = ConfigurationManager.ConnectionStrings["AppEntities"].ConnectionString;
            //connectionString = connectionString.Substring(connectionString.IndexOf("\"")).Replace("\"", String.Empty);
            //App.Domain.UtilityDAO.ConnectionString = connectionString;
            ///Initialize String => Datetime conversion rule
            App.Core.Extensions.StringExtensions.DateTimeFormatForUI = ConfigReader.CSharpCalendarDateFormat;
            ///Initialize Lucene Search engine
            App.Search.SearchConstants.ProductIndexDirectory = HttpContext.Current.Server.MapPath(AppConstants.Directories.LUCENE_PRODUCT_INDEX);
            App.Search.SearchConstants.CategoryIndexDirectory = HttpContext.Current.Server.MapPath(AppConstants.Directories.LUCENE_CATEGORY_INDEX);
        }
        /// <summary>
        /// Sends Error email to the configured ErrorEmail receiver in AppSettings.config
        /// </summary>
        /// <param name="ex"></param>
        public static void SendErrorEmail(Exception ex)
        {
            if (ex != null)
            {
                if (ex is System.Threading.ThreadAbortException)
                    return;

                StringBuilder template = new StringBuilder(WebUtil.ReadEmailTemplate(AppConstants.EmailTemplate.COMMON));
                StringBuilder sb = new StringBuilder();
                sb.AppendFormat("Dear Admin,<br/>An unhandled exception occured in <a href='{0}'>{0}</a>. Check the error details below.<br/>", WebUtil.GetDomainAddress());
                sb.AppendFormat("<b>URL:</b> {0}<br/>", HttpContext.Current.Request.Url.AbsoluteUri);
                if (HttpContext.Current.Request.UrlReferrer != null)
                    sb.AppendFormat("<b>Url Referrer:</b> {0}<br/>", HttpContext.Current.Request.UrlReferrer.AbsoluteUri);
                sb.AppendFormat("<b>Method:</b> {0}<br/>", HttpContext.Current.Request.HttpMethod);
                sb.AppendFormat("<b>User Agent:</b> {0}<br/>", HttpContext.Current.Request.UserAgent);
                if (SessionCache.CurrentUser != null)
                    sb.AppendFormat("<b>User name:</b> {0} <b>User ID:</b>{1}<br/>", SessionCache.CurrentUser.UserName, SessionCache.CurrentUser.ID);
                if (ex.InnerException == null)
                {
                    sb.AppendFormat("<h2 style='color:maroon;'><i>{0}</i></h2>", ex.Message);                    
                    sb.AppendFormat("<b><u>Stack Trace:</u></b><br/>{0}<br/>", ex.StackTrace);
                }
                else
                {
                    sb.AppendFormat("<h2 style='color:maroon;'><i>{0}</i></h2>", ex.InnerException.Message);
                    if(ex.InnerException.StackTrace.IsNullOrEmpty())
                        sb.AppendFormat("<b><u>Stack Trace:</u></b><br/>{0}<br/>", ex.StackTrace);
                    else
                        sb.AppendFormat("<b><u>InnerException Stack Trace:</u></b><br/>{0}<br/>", ex.InnerException.StackTrace);
                }
                template.Replace(AppConstants.ETConstants.MESSAGE, sb.ToString());
                template.Replace(AppConstants.ETConstants.DOMAIN, WebUtil.GetDomainAddress());
                String subject = String.Format("Error occured in {0}", WebUtil.GetDomainAddress().Replace("http://", String.Empty));
                Console.Write(template.ToString());
                WebUtil.SendMail(ConfigReader.SmtpFromEmail, ConfigReader.ErrorEmail, String.Empty, String.Empty, subject, template.ToString());                
            }
        }
    }

    #region  Value Converters
    /// <summary>
    /// Used to Convert String DateTime to DateTime Object
    /// </summary>
    public class StringToDateTimeConverter : ITypeConverter<String, DateTime>
    {       
        public DateTime Convert(ResolutionContext context)
        {
            if (context.SourceValue == null)
                return DateTime.MinValue;
            String sourceValue = ((String)context.SourceValue);
            return sourceValue.IsEmpty() ? DateTime.MinValue : sourceValue.ToDateTime(ConfigReader.CSharpCalendarDateFormat);
        }
    }
    public class StringToNullableDateTimeConverter : ITypeConverter<String, DateTime?>
    {
        public DateTime? Convert(ResolutionContext context)
        {
            if (context.SourceValue == null)
                return null; //DateTime.MinValue;
            String sourceValue = ((String)context.SourceValue);
            if (sourceValue.IsEmpty())
                return null;
            return sourceValue.ToDateTime(ConfigReader.CSharpCalendarDateFormat);
            //return sourceValue.IsEmpty() ? null : sourceValue.ToDateTime(ConfigReader.CSharpCalendarDateFormat);
        }
    }

    /// <summary>
    /// Used to Convert DateTime object to String, that will be shown to the UI for edit
    /// </summary>
    public class DateTimeToStringConverter : ITypeConverter<DateTime, String>
    {
        public String Convert(ResolutionContext context)
        {
            if (context.SourceValue == null)
                return String.Empty;

            DateTime sourceValue = ((DateTime)context.SourceValue);
            return sourceValue == DateTime.MinValue ? String.Empty : sourceValue.ToString(ConfigReader.CSharpCalendarDateFormat);
        }
    }

    public class StringToBoolean : ITypeConverter<String, Boolean>
    {
        public bool Convert(ResolutionContext context)
        {
            if (context.SourceValue == null)
                return false;

            return NullHandler.GetString(context.SourceValue).ToBoolean();            
        }
    }
    public class BooleanToString : ITypeConverter<bool, String>
    {
        public string Convert(ResolutionContext context)
        {
            if (context.SourceValue == null)
                return String.Empty;

            return context.SourceValue.ToString();
        }
    }

    public class IntToNullableInt : ITypeConverter<int, int?>
    {
        public int? Convert(ResolutionContext context)
        {
            if (context.SourceValue == null)
                return null;
            
            if (NullHandler.GetInt(context.SourceValue) == 0)
                return null;

            return NullHandler.GetInt(context.SourceValue);
        }
    }

    //public class DateTimeToStringResolver : ValueResolver<App.Domain.User, String>
    //{
    //    protected override string ResolveCore(App.Domain.User source)
    //    {
    //        if (source.ModifiedOn == DateTime.MinValue)
    //            return String.Empty;
    //        else
    //            return source.ModifiedOn.ToString(ConfigReader.JSCalendarDateFormat);
    //    }        
    //}
    //public class StringToDateTimeResolver : ValueResolver<String, DateTime>
    //{
    //    protected override DateTime ResolveCore(string source)
    //    {
    //        if (source.IsEmpty())
    //            return DateTime.MinValue;
    //        else
    //            return source.ToDateTime(ConfigReader.CSharpCalendarDateFormat);
    //    }
    //}

    #endregion Value Converters
}